﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WPLDB.DA.Interfaces;
using WPLDB.DA.Models;
using WPLDB.Utility.Extensions;

namespace WPLDB.Code
{
    /// <summary>
    /// This class helps to created table class for tables C# code 
    /// and variables naming are not explicit required the explanations
    /// </summary>
    public class CreateTableClassCode : ICreateClassCode
    {
        #region "Variable"

        private TableModel _model;

        #endregion

        #region "ctor"

        public CreateTableClassCode(TableModel model)
        {
            _model = model;
        }

        #endregion

        #region "Constants"

        string CLASS = "[T][Table][NEWLINE][T]public class [CLASSNAME] : TableBase[NEWLINE][T]{[NEWLINE]" +
            "[T][T]public [CLASSNAME]()[NEWLINE][T][T]{" +
            "[CONSTRUCTORCONTENT]" +
            "[NEWLINE][T][T]}[NEWLINE]" +
            "[LISTOFPROPERTIES][NEWLINE]" +
            "[NEWLINE][T]}[NEWLINE][NEWLINE]";
        string PROPERTY = "[NEWLINE][T][T]private [PROPERTYTYPE] _[PROPERTY];[NEWLINE]" +
            "[T][T][Column][NEWLINE][T][T]public [PROPERTYTYPE] [PROPERTY]" +
            "[NEWLINE][T][T]{[NEWLINE]" +
            "[T][T][T]get { return _[PROPERTY]; }[NEWLINE]" +
            "[T][T][T]set { base.set(() => [PROPERTY], ref _[PROPERTY], value); }" +
            "[NEWLINE][T][T]}[NEWLINE]";
        string ENTITYSET = "[NEWLINE][T][T]private EntitySet<[PROPERTYSINGULAR]> _[PROPERTYPLURAL]_[FOREIGN]_[THISKEY];[NEWLINE]" +
            "[T][T][Association(Storage = \"_[PROPERTYPLURAL]_[FOREIGN]_[THISKEY]\", ThisKey = \"[THISKEY]\", OtherKey = \"[OTHERKEY]\")][NEWLINE]" +
            "[T][T]public EntitySet<[PROPERTYSINGULAR]> [PROPERTYPLURAL]_[FOREIGN]_[THISKEY][NEWLINE]" +
            "[T][T]{[NEWLINE]" +
            "[T][T][T]get { return this.[PROPERTYPLURAL]_[FOREIGN]_[THISKEY]; }[NEWLINE]" +
            "[T][T][T]set { this.[PROPERTYPLURAL]_[FOREIGN]_[THISKEY].Assign(value); }[NEWLINE]" +
            "[T][T]}[NEWLINE]" +
            "[NEWLINE][T][T]private void attach[FOREIGN][THISKEY]([PROPERTYSINGULAR] [PROPERTYSINGULAR])[NEWLINE]" +
            "[T][T]{[NEWLINE]" +
            "[T][T][T]base.OnPropertyChanging(() => [PROPERTYSINGULAR]);[NEWLINE]" +
            "[T][T]}[NEWLINE]" +
            "[NEWLINE][T][T]private void detach[FOREIGN][THISKEY]([PROPERTYSINGULAR] [PROPERTYSINGULAR])[NEWLINE]" +
            "[T][T]{[NEWLINE]" +
            "[T][T][T]base.OnPropertyChanging(() => [PROPERTYSINGULAR]);[NEWLINE]" +
            "[T][T]}[NEWLINE]";
        string ENTITYSETCONSTRUCTOR = "[NEWLINE][T][T][T]_[PROPERTYPLURAL]_[FOREIGN]_[THISKEY] = new EntitySet<[PROPERTYSINGULAR]>(new Action<[PROPERTYSINGULAR]>(this.attach[FOREIGN][THISKEY]), new Action<[PROPERTYSINGULAR]>(this.detach[FOREIGN][THISKEY]));";

        string ENTITYREF = "[NEWLINE][T][T]private EntityRef<[PROPERTYSINGULAR]> _[PROPERTYSINGULAR]_[FOREIGN]_[THISKEY];[NEWLINE]" +
            "[NEWLINE]" +
            "[T][T][Association(Storage = \"_[PROPERTYSINGULAR]_[FOREIGN]_[THISKEY]\", ThisKey = \"[THISKEY]\", OtherKey = \"[OTHERKEY]\", IsForeignKey = true)][NEWLINE]" +
            "[T][T]public [PROPERTYSINGULAR] [PROPERTYSINGULAR]_[FOREIGN]_[THISKEY][NEWLINE]" +
            "[T][T]{[NEWLINE]" +
            "[T][T][T]get { return _[PROPERTYSINGULAR]_[FOREIGN]_[THISKEY].Entity; }[NEWLINE]" +
            "[T][T][T]set[NEWLINE]" +
            "[T][T][T]{[NEWLINE]" +
             "[T][T][T][T]base.OnPropertyChanging(() => [PROPERTYSINGULAR]_[FOREIGN]_[THISKEY]);[NEWLINE]" +
             "[T][T][T][T]_[PROPERTYSINGULAR]_[FOREIGN]_[THISKEY].Entity = value;[NEWLINE]" +
             "[T][T][T][T]if (null != value)[NEWLINE]" +
             "[T][T][T][T]{[NEWLINE]" +
             "[T][T][T][T][T][THISKEY] = value.[OTHERKEY];[NEWLINE]" +
             "[T][T][T][T]}[NEWLINE]" +
             "[T][T][T][T]base.OnPropertyChanged(() => [PROPERTYSINGULAR]_[FOREIGN]_[THISKEY]);[NEWLINE]" +
             "[NEWLINE]" +
             "[T][T][T]}[NEWLINE]" +
             "[T][T]}[NEWLINE]";



        string PRIMARYKEYATTRIBUTE = "[NEWLINE][T][T]//PrimaryKey Property[NEWLINE][T][T][Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = \"INT NOT NULL Identity\", CanBeNull = false, AutoSync = AutoSync.OnInsert)]";

        #endregion

        #region "Interface Implementation"

        public string GenerateClassString()
        {
            var properties = new StringBuilder();
            var constructor = new StringBuilder();


            if (null != _model && null != _model.ListOfColumns)
                foreach (var item in _model.ListOfColumns)
                    properties.Append(PROPERTY
                        .Replace("[Column]", item.IsPrimaryKey ? PRIMARYKEYATTRIBUTE.ReplaceNewLine() : "[Column]")
                        .ReplaceProperty(item.Name.RemoveSpecialChar().ReplaceCSharpKeyWords())
                        .ReplacePropertyType(item.Type)
                        .ReplaceNewLine());

            if (null != _model && null != _model.ListOfEntityRef)
                foreach (var item in _model.ListOfEntityRef)
                    properties.Append(ENTITYREF
                        .ReplacePropertySingular(item.EntityName.Singular)
                        .ReplacePropertyThisKey(item.ThisKey.RemoveSpecialChar().ReplaceCSharpKeyWords())
                        .ReplacePropertyOtherKey(item.OtherKey.RemoveSpecialChar().ReplaceCSharpKeyWords())
                        .ReplaceForeignKey(item.EntityKey)
                        .ReplaceNewLine());

            if (null != _model && null != _model.ListOfEntitySet)
                foreach (var item in _model.ListOfEntitySet)
                {
                    properties.Append(ENTITYSET
                        .ReplacePropertySingular(item.EntityName.Singular)
                        .ReplacePropertyPlural(item.EntityName.Plural)
                        .ReplacePropertyThisKey(item.ThisKey.RemoveSpecialChar().ReplaceCSharpKeyWords())
                        .ReplacePropertyOtherKey(item.OtherKey.RemoveSpecialChar().ReplaceCSharpKeyWords())
                        .ReplaceForeignKey(item.EntityKey)
                        .ReplaceNewLine());

                    constructor.Append(ENTITYSETCONSTRUCTOR
                        .ReplacePropertySingular(item.EntityName.Singular)
                        .ReplacePropertyPlural(item.EntityName.Plural)
                        .ReplacePropertyThisKey(item.ThisKey.RemoveSpecialChar().ReplaceCSharpKeyWords())
                        .ReplaceForeignKey(item.EntityKey)
                        .ReplaceNewLine());
                }

            return CLASS
                .ReplaceClass(_model.Name.Singular)
                .ReplaceListOfProperties(properties.ToString())
                .ReplaceConstructorContent(constructor.ToString())
                .Replace_at()
                .ReplaceNewLine();
        } 
        #endregion
    }
}
